#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>
#define SERVER_PORT 6666

/*
监听后，一直处于accept阻塞状态，
直到有客户端连接，
当客户端如数quit后，断开与客户端的连接
*/
char mail_content_sql[50000], datetime_sql[30]; //datetime "YY-mm-dd hh-mm-ss"固定长度为17
int receiver_num_sql[5000];
char sender_cx[20], receiver_cx[20], content_cx[500];
int main()
{

    //调用socket函数返回的文件描述符

    int serverSocket;

    //声明两个套接字sockaddr_in结构体变量，分别表示客户端和服务器

    struct sockaddr_in server_addr;

    struct sockaddr_in clientAddr;

    int addr_len = sizeof(clientAddr);

    int client;

    char buffer[200];

    int iDataNum;

    //socket函数，失败返回-1
    //int socket(int domain, int type, int protocol);
    //第一个参数表示使用的地址类型，一般都是ipv4，AF_INET
    //第二个参数表示套接字类型：tcp：面向连接的稳定数据传输SOCK_STREAM
    //第三个参数设置为0
    if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        return 1;
    }

    bzero(&server_addr, sizeof(server_addr));

    //初始化服务器端的套接字，并用htons和htonl将端口和地址转成网络字节序
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);

    //ip可是是本服务器的ip，也可以用宏INADDR_ANY代替，代表0.0.0.0，表明所有地址
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    //对于bind，accept之类的函数，里面套接字参数都是需要强制转换成(struct sockaddr *)
    //bind三个参数：服务器端的套接字的文件描述符，


    

    if (bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("connect");
        return 1;
    }

    //设置服务器上的socket为监听状态
    if (listen(serverSocket, 5) < 0)
    {
        perror("listen");
        return 1;
    }

    while (1)
    {
	
	
        printf("监听端口: %d\n", SERVER_PORT);

        //调用accept函数后，会进入阻塞状态
        //accept返回一个套接字的文件描述符，这样服务器端便有两个套接字的文件描述符，
        //serverSocket和client。
        //serverSocket仍然继续在监听状态，client则负责接收和发送数据
        //clientAddr是一个传出参数，accept返回时，传出客户端的地址和端口号
        //addr_len是一个传入-传出参数，传入的是调用者提供的缓冲区的clientAddr的长度，以避免缓冲区溢出。
        //传出的是客户端地址结构体的实际长度。
        //出错返回-1
        client = accept(serverSocket, (struct sockaddr *)&clientAddr, (socklen_t *)&addr_len);

        if (client < 0)
        {
            perror("accept");
            continue;
        }

       // printf("等待消息...\n");
        //inet_ntoa ip地址转换函数，将网络字节序IP转换为点分十进制IP
        //表达式：char *inet_ntoa (struct in_addr);
        printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
        printf("Port is %d\n", htons(clientAddr.sin_port));

        while (1)
        {
            printf("读取消息:");
            buffer[0] = '\0';
            iDataNum = recv(client, buffer, 1024, 0);
            printf("\nbuffer is %s\n",buffer);
            analyze(buffer,client);

            //if (strcmp(buffer, "quit") == 0)
           //     break;
        }
   
    }
    close(serverSocket);
    return 0;
}

void analyze(char *buff,int client)
{
    printf("这是analysis的buff串%s\n", buff);
    int lon = (int)buff[0] - '0'; //获取总长度
    int funum = (int)buff[1] - '0';
    char lanch[20];
    lanch[0]='\0';
    switch (funum)
    {
    case 1: //实现注册函数
    {
        for (int i = 2; i <= strlen(buff) + 1; i++)
            lanch[i - 2] = buff[i];
        zhuce(lanch);
    }
    break;

    case 2: //实现登录函数
    {
        for (int i = 2; i <= strlen(buff) + 1; i++)
            lanch[i - 2] = buff[i];
        denglu(lanch,client);
    }
    break;

    case 3: //实现读信函数
    {
        for (int i = 2; i <= strlen(buff) + 1; i++)
            lanch[i - 2] = buff[i];
        duxin(lanch,client);
    }

    case 4: //实现写信函数
    {
        for (int i = 2; i <= strlen(buff) + 1; i++)
            lanch[i - 2] = buff[i];
        cunxin(lanch);
    }
    break;
    default:;
    }
}

void denglu(char cont[4096],int client)
{
 
    char name[100];
    char passwd[100];
    name[0]='\0';
    passwd[0]='\0';
    printf("%s\n",cont);
    int a = cont[0] - '0';
    for (int i = 1; i <= a; i++)
        name[i - 1] = cont[i];
    int b = cont[a + 1] - '0';
    for (int i = a + 2; i <= a + b + 1; i++)
        passwd[i - 2 - a] = cont[i];
        
        name[a]='\0';
        passwd[b+1]='\0';
        
        
        printf("%s%s\n",name,passwd);

    if (denglu_sql(name, passwd) == 1)
    {
    printf("dengluchenggong\n");
     SendSockChar(client, 'D') ;//发送一个同步字符，参数为套接字号和一个待发送的字符。该函数将一个字符写入套接字中，即发送给对方
       
    }
    else
    {
     printf("denglushibai\n");
     SendSockChar( client, 'F') ;//发送一个同步字符，参数为套接字号和一个待发送的字符。该函数将一个字符写入套接字中，即发送给对方 
    }
}

int zhuce(char cont[4096])
{
    // printf("1111");
    char name[100];
    printf("%s\n", cont);
    char passwd[100];
    int a = (int)cont[0] - '0';
    for (int i = 1; i <= a; i++)
        name[i - 1] = cont[i];
    int b = (int)cont[a + 1] - '0';
    for (int i = a + 2; i <= a + b + 1; i++)
        passwd[i - 2 - a] = cont[i];

    if (zhuce_sql(name, passwd, a, b))
    {
        name[a] = '\0';
        passwd[b] = '\0';
        printf("%s\n%s\n", name, passwd);
        //printf("注册成功");
    }
}

int duxin(char *temp,int client)
{
    int num;
    num = temp[0] - '0';
    read_mail_sql(num);
    printf("%s", mail_content_sql);
    write(client,mail_content_sql,1024);
}

int cunxin(char *cont)
{
    memset(sender_cx, 0, sizeof(sender_cx));
memset(receiver_cx, 0, sizeof(receiver_cx));
memset(content_cx, 0, sizeof(content_cx));

    int a = cont[0] - '0';
    for (int i = 1; i <= a; i++)
        sender_cx[i - 1] = cont[i];
    int b = cont[a + 1] - '0';
    for (int i = a + 2; i <= a + b+1; i++)
        receiver_cx[i - a - 2] = cont[i];
    int c = cont[a + b + 2] - '0';
    for (int i = a + b + 3; i <= a + b + c + 2; i++)
        content_cx[i - a - b - 3] = cont[i];
    printf("%s\n%s\n%s\n", sender_cx, receiver_cx, content_cx);
	printf("wzl存信函数里面的信长为%d",strlen(content_cx));
    chucun_sql();
}

int zhuce_sql(char a[20], char b[20], int a_1, int b_1) //注册函数 a是用户名 b是密码 返回1注册成功 0失败
{
    MYSQL *conn_ptr;
    /*MYSQL_RES *res_ptr; 
    MYSQL_ROW sqlrow; 
    MYSQL_FIELD *fd; */
    int res, i, j, m, y;
    char x[20], sqll[10000];

    conn_ptr = mysql_init(NULL);
    if (!conn_ptr)
    {
        printf("mysql_init failed\n");
        return EXIT_FAILURE;
    }
    conn_ptr = mysql_real_connect(conn_ptr, "localhost", "root", "123456", "test", 3306, NULL, 0);
    if (conn_ptr)
    {

        memset(sqll, 0, sizeof(sqll));
        a[a_1] = '\0';
        b[b_1] = '\0';
        sprintf(sqll, "insert into users (user,password) values('%s','%s')", a, b);
        res = mysql_query(conn_ptr, sqll); //可以把insert语句替换成delete或者update语句，都一样的
                                           //      res = mysql_query(conn_ptr, "delete from user where name = 'Ann' and age < 10");
        if (!res)
        { //输出受影响的行数
            printf("Inserted %lu rows\n", (unsigned long)mysql_affected_rows(conn_ptr));
            return 1;
        }
        else
        { //打印出错误代码及详细信息
            printf("primarykey error,already hava usr");
            return -1;
            //fprintf(stderr, "Insert error %d: %sn",mysql_errno(conn_ptr),mysql_error(conn_ptr));
        }
    }
    else
    {
        printf("244");
        return -2;
        //printf("Connection failed\n");
    }

    mysql_close(conn_ptr);
}

int denglu_sql(char a[20], char b[20]) //登录函数 a是用户名 b是密码 1为密码正确 0为密码错误 -1为不存在该用户
{
    MYSQL *conn_ptr = NULL;
    MYSQL_RES *res_ptr;
    MYSQL_ROW sqlrow;
    MYSQL_FIELD *fd;
    int res, i, j, m, y;
    char x[20], sqll[10000];
    conn_ptr = mysql_init(NULL);
    if (!conn_ptr)
    {
        return EXIT_FAILURE;
    }

    conn_ptr = mysql_real_connect(conn_ptr, "localhost", "root", "123456", "test", 3306, NULL, 0);
    if (conn_ptr)
    {
        memset(sqll, 0, sizeof(sqll));
        sprintf(sqll, "select password from users where user='%s'", a);
        res = mysql_query(conn_ptr, sqll); //查询语句
        if (res)
        {
            //printf("SELECT error:%s\n",mysql_error(conn_ptr));
            return -1;
        }
        else
        {
            res_ptr = mysql_store_result(conn_ptr);
            //取出结果集
            //  if(res_ptr) ;

            // printf("%lu Rows\n",(unsigned long)mysql_num_rows(res_ptr));
            j = mysql_num_fields(res_ptr);

            sqlrow = mysql_fetch_row(res_ptr);
            /*while((sqlrow = mysql_fetch_row(res_ptr)))  {   //依次取出记录 
                    for(i = 0; i < j; i++)  
			x[i]=sqlrow[i];        
                        printf("%s\t", sqlrow[i]);              //输出 
                    printf("\n");   */

            // }
            if (!(sqlrow))
                return -1;
            //printf("%s\n",sqlrow[0]);
            strcpy(x, sqlrow[0]);
            // printf("x=%s\n,b=%s\n",x,b);
            y = strlen(x);
            m = strlen(b);
            // printf("y=%d,m=%d",y,m);
            if (m != y)
                return 0;
            //printf("%d\n",y);
            for (i = 0; i < y; i++)
            {
                if (x[i] != b[i])
                    return 0;
            }
            return 1;
            if (mysql_errno(conn_ptr))
            {
                return 2; //fprintf(stderr,"Retrive error:s\n",mysql_error(conn_ptr));
            }
        }
        mysql_free_result(res_ptr);
    }
    else
    {
        return -1;
    }
    mysql_close(conn_ptr);
}

void chucun_sql() //输入发件人，收件人，信的内容
{
    MYSQL *conn_ptr;
	printf("klklkl\n");
    printf("386");
    int res, i, j, m, y;
    printf("388");
    char x[20], sqll[10000];
    printf("390");
    int num_sql;
    printf("392");
    
    
    
    num_sql = get_maxnum_sql()+1;
    //int num_sql++;
    printf("%d\n",num_sql);
    conn_ptr = mysql_init(NULL);
    if (!conn_ptr)
    {
        printf("mysql_init failed\n");
        // return EXIT_FAILURE;
    }
    conn_ptr = mysql_real_connect(conn_ptr, "localhost", "root", "123456", "test", 3306, NULL, 0);
    if (conn_ptr)
    {
        int a, b, c;
        a = strlen(sender_cx);
        b = strlen(receiver_cx);
        c = strlen(content_cx);
        printf("%d\n%d\n%d\n", a, b, c);
        sender_cx[a] = '\0';
        receiver_cx[b] = '\0';
        content_cx[c] = '\0';
        //printf("okkk");
        memset(sqll, 0, sizeof(sqll));
        sprintf(sqll, "insert into mail (sender,receiver,content,num,panduan) values('%s','%s','%s','%d','0')", sender_cx, receiver_cx, content_cx, num_sql);
        res = mysql_query(conn_ptr, sqll); //可以把insert语句替换成delete或者update语句，都一样的
        printf("okkk");                                   //      res = mysql_query(conn_ptr, "delete from user where name = 'Ann' and age < 10");
        if (!res)
        { //输出受影响的行数
            printf("Inserted %lu rows\n", (unsigned long)mysql_affected_rows(conn_ptr));
            //return 1;
        }
        else
        { //打印出错误代码及详细信息
            printf("primarykey error,already hava usr");
            // return -1;
            //fprintf(stderr, "Insert error %d: %sn",mysql_errno(conn_ptr),mysql_error(conn_ptr));
        }
    }
    else
    {
        printf("427");
        //return -2;
        //printf("Connection failed\n");
    }

    mysql_close(conn_ptr);
}

int get_maxnum_sql() //获取最大值
{
    printf("437");
    MYSQL *conn_ptr;
    MYSQL_RES *res_ptr;
    MYSQL_ROW sqlrow;
    MYSQL_FIELD *fd;
    int res, i, j, mmaxnum;
    char maxnum[1000];
    conn_ptr = mysql_init(NULL);
    if (!conn_ptr)
    {
        return EXIT_FAILURE;
    }
    conn_ptr = mysql_real_connect(conn_ptr, "localhost", "root", "123456", "test", 3306, NULL, 0);
    if (conn_ptr)
    {
        res = mysql_query(conn_ptr, "select Max(num) from mail"); //查询语句
        if (res)
        {
            printf("SELECT error:%s\n", mysql_error(conn_ptr));
        }
        else
        {
            res_ptr = mysql_store_result(conn_ptr); //取出结果集
            if (res_ptr)
            {
                // printf("%lu Rows\n",(unsigned long)mysql_num_rows(res_ptr));
                j = mysql_num_fields(res_ptr);
                while ((sqlrow = mysql_fetch_row(res_ptr)))
                { //依次取出记录
                    for (i = 0; i < j; i++)
                        strcpy(maxnum, sqlrow[i]);
                    //printf("%s\t", sqlrow[i]);              //输出
                    //    printf("\n");
                }
                mmaxnum = maxnum[0] - '0';

                if (mysql_errno(conn_ptr))
                {
                    fprintf(stderr, "Retrive error:s\n", mysql_error(conn_ptr));
                }
            }
            mysql_free_result(res_ptr);
           
        }
    }
    else
    {
        printf("Connection failed\n");
    }
    printf("486");
    mysql_close(conn_ptr);
	 return mmaxnum;
}

void read_mail_sql(int num) //输入邮件编号num 把邮件存到全局变量mail_content_sql
{
    memset(mail_content_sql, 0, sizeof(mail_content_sql));
    MYSQL *conn_ptr;
    MYSQL_RES *res_ptr;
    MYSQL_ROW sqlrow;
    MYSQL_FIELD *fd;
    int res, i, j;
    char sqll[5000];
    conn_ptr = mysql_init(NULL);
    if (!conn_ptr)
    {
        return EXIT_FAILURE;
    }
    conn_ptr = mysql_real_connect(conn_ptr, "localhost", "root", "123456", "test", 3306, NULL, 0);
    if (conn_ptr)
    {
        memset(sqll, 0, sizeof(sqll));
        sprintf(sqll, "select content from mail where num = '%d'", num);
        res = mysql_query(conn_ptr, sqll); //查询语句
        if (res)
        {
            // printf("SELECT error:%s\n",mysql_error(conn_ptr));
        }
        else
        {
            res_ptr = mysql_store_result(conn_ptr); //取出结果集
            if (res_ptr)
            {
                //printf("%lu Rows\n",(unsigned long)mysql_num_rows(res_ptr));
                j = mysql_num_fields(res_ptr);
                while ((sqlrow = mysql_fetch_row(res_ptr)))
                { //依次取出记录
                    for (i = 0; i < j; i++)
                        strcpy(mail_content_sql, sqlrow[i]);
                    // printf("%s\t", sqlrow[i]);              //输出
                    //printf("\n");
                }
                if (mysql_errno(conn_ptr))
                {
                    //fprintf(stderr,"Retrive error:s\n",mysql_error(conn_ptr));
                }
            }
            mysql_free_result(res_ptr);
            haveread_sql(num);
        }
    }
    else
    {
        // printf("Connection failed\n");
    }
    mysql_close(conn_ptr);
}

void haveread_sql(int num) //使num已读
{
    MYSQL *conn_ptr;
    int res;
    char sqll[100];
    conn_ptr = mysql_init(NULL);
    if (!conn_ptr)
    {
        printf("mysql_init failed\n");
        // return EXIT_FAILURE;
    }
    conn_ptr = mysql_real_connect(conn_ptr, "localhost", "root", "123456", "test", 3306, NULL, 0);
    if (conn_ptr)
    {
        memset(sqll, 0, sizeof(sqll));
        sprintf(sqll, "update mail set panduan='1' where num ='%d'", num);
        res = mysql_query(conn_ptr, sqll); //可以把insert语句替换成delete或者update语句，都一样的
        if (!res)
        { //输出受影响的行数
            // printf("Inserted %lu rows\n",(unsigned long)mysql_affected_rows(conn_ptr));
        }
        else
        { //打印出错误代码及详细信息
            // fprintf(stderr, "Insert error %d: %sn",mysql_errno(conn_ptr),mysql_error(conn_ptr));
        }
    }
    else
    {
        printf("Connection failed\n");
    }
    mysql_close(conn_ptr);
}


char GetSockChar(int sockfd) //接受SendSockChar()发来的同步字符
{
    char ch;
    do
    {
        read(sockfd, &ch, 1);
    } while (!isalnum(ch)); //使用while循环，直到督导有效的同步字符位置
    return ch;              //返回读到的同步字符
}

void SendSockChar(int sockfd, char ch) //发送一个同步字符，参数为套接字号和一个待发送的字符。该函数将一个字符写入套接字中，即发送给对方
{
    write(sockfd, &ch, 1); //发送成功返回OK
}
